/* eslint-disable no-useless-escape */
/* eslint-disable no-inner-declarations */
//LiteLoaderScript Dev Helper
/// <reference path="d:/Game/MCBE/Server/LiteloaderSE/JS/HelperLib-master/src/index.d.ts"/> 

/* jshint esversion: 6 */
/*jshint -W069 */

const INFO = {
    name: "LF_Music",
    intro: "在服务器里播放音乐",
    version: [0, 14, 4],
    other: {
        auth: "FlyLight、 Wn1027",
        group_QQ: "FlyLight -> 641223836",
        thanks: "Wn1027"
    }
};
/* 
0.13.0
- 自定义全服背景音乐
- 网络音乐下载
- 音乐可隐藏 
- 修复全服播放无法添加播放队列的问题(loop改为play_once)

0.14.0
- 适配LL3
- ffmpeg.exe 路径从./plugins/LF_Music/DATA/music/ 移动到 ./plugins/LF_Music/tools/下
- BGM.json 路径从./plugins/LF_Music/ 移动到 ./plugins/LF_Music/DATA/下
- 歌词栏位置从BossBar更改为音乐盒消息
- 播放音乐默认只播放一次, 如有需要在播放时选择<自动播放下一首>
- 修复关闭顶部歌词显示时仍然跳出歌词的问题
- 修复ffmpeg音频格式自动转换
*/


ll.registerPlugin(INFO.name, INFO.intro, INFO.version, INFO.other);

//设置输出日志
logger.setConsole(true, 4);

const PATH = {
    MAIN: "./plugins/LF_Music",
    MUSIC: "./plugins/LF_Music/DATA/music",
    DATA: "./plugins/LF_Music/DATA/data.json",
    MUSICLIST: "./plugins/LF_Music/DATA/musicList.json",
};

// 获取存档名称
var regular = /level-name=(.*)/;
var serverconfig =  File.readFrom('./server.properties');
var levelname = regular.exec(serverconfig)[1];
var default_config = {
    "sounds":{
        "postfix": ["ogg"],
        "stream": true,
        "?stream": "是否以流线播放，用于缓解时间较长的音效产生的卡顿，也决定在未播放完音效下播放同一音效是否会叠加，流线情况下不会叠加则为重新播放。"
    },
    "usrGUI":{
        "enable": true,
        "itemGUI": "minecraft:music_disc",
        "?itemGUI": "手持该物品点击地面可以召唤音乐菜单",
        "defaultTEXT": "{musicname}",
        "?defaultTEXT": "菜单音乐列表的展示样式，可自定义修改为 §b《{musicName}》等",
        "playerJoinMusicVolume": 20,
        "?playerJoinMusicVolume": "入服音乐音量(0~100)",
        "musicCMD": {
            "enable": true
        },
        "playsoundCMD": {
            "enable": true
        },
    },
    "PackUUID":"f3f55c4c-991a-4158-9ae3-5cf7b2848072",
    "serverRES": "./development_resource_packs/serverMusicRE/",
    "worldJson": "./worlds/Bedrock level/world_resource_packs.json",
    "?worldJSon":"置于服务器当前存档目录下",
    "worldJsonLock":false,
    "version": [0,0,1],
    "reference": false
};



//=================
//变量定义及说明
var config = new JsonConfigFile(PATH.MAIN + "/config.json",JSON.stringify(default_config)); //配置文件
var DataCfg = new JsonConfigFile(PATH.DATA, `{"_version_":[0,11,0],"music":{}}`); //服务器音乐数据信息data.json
let bgm_cfg = new JsonConfigFile(`${PATH.MAIN}/DATA/BGM.json`, JSON.stringify({enabled: false, volume: 0.1, playList:[], minRandomInterval: 5, maxRandomInterval: 15})); // 全服BGM配置文件
var musicList_config = new JsonConfigFile(PATH.MUSICLIST, `{}`); // 玩家保存的音乐列表
var DataArry = DataCfg.get("music"); //服务器所有音乐信息
var PackUUID = config.get("PackUUID"); // 资源包uuid
var PackVersion = config.get('version'); // 资源包版本
var done = 0; // 异步函数完成数（音频多线程转换）
var PlayList = {}; // 所有玩家的当前播放列表

//musicName: 音乐文件名（不带后缀）
//musicFileName: 音乐文件名(带后缀)
//musicReName: 音乐重命名
//musicMcName: 游戏内音乐命名空间（music.game.musicName || record.musicName）

var RUNTIME = 0; // 显示歌词的绝对时间（毫秒）
var bias = -50; // 歌词时间全局偏移(毫秒)
var LRCdata = {}; // 读取歌词长期存在内存中                                                                                    
var CurrentMusic = {}; // 当前显示歌词的信息，控制什么时候显示歌词

let BGM_enabled = bgm_cfg.get("enabled");
let cache_BGMlist = []; // 还未播放的的BGM列表
let CurrentBGM = { // 当前正在播放的BGM
    musicName: "",
    endTime: 0
};
//=================


// 更新config （服务器启动后执行）
function configUpdata(){
    // 0.8.3 config更新
    var configGUI = config.get('usrGUI');
    if (configGUI['itemGUI'] == undefined){
        configGUI['itemGUI'] = "minecraft:music_disc";
        configGUI['?itemGUI'] = "手持该物品点击地面可以召唤音乐菜单";
    }

    // 0.8.5  config更新
    if (configGUI["svrLoopPlay"] == undefined){
        configGUI["svrLoopPlay"] = true;
        configGUI["?svrLoopPlay"] = "关闭后仅OP可全服循环播放";
        configGUI["maxRadius"] = -1;
        configGUI["?maxRadius"] = "玩家播放的最大半径(OP不受此限制)";
        configGUI["playerJoinMusic"] = "无";
    }

    // 0.10.0  config更新
    if (configGUI["lrc"] == undefined){
        configGUI["lrc"] = true;
        configGUI["?lrc"] = "歌词显示总开关";
        config.set("usrGUI", configGUI);
    }

    // 0.11.0  config音频转换质量更新
    if(config.get("AudioConversionQuality") == undefined){
        config.set("AudioConversionQuality", "低质量");
    }
    
    // 0.11.0 data.json 更新
    if (DataCfg.get("_version_") == undefined){
        if (!File.exists(`${PATH.MUSIC}/Backup`)){
            File.createDir(`${PATH.MUSIC}/Backup/`);
        }
        if (File.exists(`${PATH.MUSIC}/Backup/data0_10_1.json`)){
            File.delete(`${PATH.MUSIC}/Backup/data0_10_1.json`);
        }
        File.copy(PATH.DATA, `${PATH.MUSIC}/Backup/data0_10_1.json`);

        var newDataArry = {"_version_":[0,11,0], "music":{}};
        for (let i = 0; i<DataArry.length; i++){
            newDataArry["music"][DataArry[i]["index"]] = {
                "rename": DataArry[i]["rename"],
                "author": DataArry[i]["author"],
                "duration": DataArry[i]["duration"]
            };
        }
        DataCfg.write(JSON.stringify(newDataArry, null, 4));
        DataArry = DataCfg.get("music");
        logger.warn("音乐信息格式(data.json) 已更新到 0,11,0");
        logger.warn("如ffmpeg.exe已放入，请输入refmusic 或 在游戏内插件配置菜单更新歌曲时长信息。");
    }

    if (configGUI["lrcDisplay"] == undefined){
        configGUI["lrcDisplay"] = "Popup";
        configGUI["?lrcDisplay"] = "默认歌词显示位置: 音乐盒消息(Popup) Boss栏(Bossbar)";
        config.set("usrGUI", configGUI);
    }

}


mc.listen("onServerStarted", function () {
    // 更新config
    configUpdata();

    // 检查资源包是否存在
    if (File.exists(config.get("serverRES")) == false) {
        //无资源包不执行动作
        setTimeout(function(){
            logger.error(`请将资源包放到${config.get("serverRES")}`);
        }, 2000);
    } else if (File.getFilesList(config.get("serverRES")).length < 4) {
        setTimeout(function(){
            logger.error(`请检查资源包完整性`);
        }, 2000);
    }


    // 新建worldjson
    if (File.exists(config.get("worldJson")) == false) {
        if ((File.getFilesList('./worlds/') != null || File.getFilesList('./worlds/').length != 0)&&(config.get('worldJsonLock')==false||config.get('worldJsonLock')==null)) {
            //config.set('worldJson', './worlds/' + File.getFilesList('./worlds/')[0] + '/world_resource_packs.json')
            config.set('worldJson', './worlds/' + levelname + '/world_resource_packs.json');
            config.set('worldJsonLock',true);
            config.reload();
        }
        let wRES = new JsonConfigFile(config.get("worldJson"), `[]`);
        wRES.close();
    }
    if (File.exists(PATH.MUSIC) == false) {
        File.mkdir(PATH.MUSIC);
    }
    registerCmd();
    log(`LF_Music ${INFO.version} 服务器音乐_加载成功 | by FlyLight & Wn1027`);
});

function registerCmd(){
    var cmd = mc.newCommand("refmusic", "刷新LF_muic的音乐文件", PermType.GameMasters); //PermType.Any: 任何人,  PermType.GameMasters: 仅OP, PermType.Console: 仅控制台
    cmd.overload([]);
    cmd.setCallback((_cmd, _ori, out, res) => {
        //logger.debug(`命令执行的主体: ${_ori.type}`); 玩家：0 控制台 7
        refMusic();
        out.success('已执行 LF_Music 音乐文件刷新命令');
    });
    cmd.setup();
    if (config.get('usrGUI')['enable'] == true){
        let guicmd = mc.newCommand("mucmenu", "召唤音乐菜单", PermType.Any);
        guicmd.setEnum("ChangeAction", ["debug"]);
        guicmd.setEnum("CurlAction", ["curl"]);
        guicmd.mandatory("action", ParamType.Enum, "ChangeAction", 1);
        guicmd.mandatory("action", ParamType.Enum, "CurlAction", 1);
        guicmd.mandatory("debugMode", ParamType.Bool);
        guicmd.mandatory("fileName", ParamType.String);
        guicmd.mandatory("url", ParamType.String);
        guicmd.overload([]);
        guicmd.overload(["ChangeAction", "debugMode"]);
        guicmd.overload(["CurlAction", "fileName", "url"]);
        guicmd.setCallback((_cmd, _ori, out, res) => {
            let pl = _ori.player;
            switch(res.action){
                case 'curl':
                    if (!(pl == null || pl.isOP() == true)){
                    out.error('此命令仅管理员可执行');
                        return;
                    }
                    system.newProcess(`curl.exe -o "${PATH.MUSIC}/${res.fileName}" -L "${res.url}"`, (_exitcode, _output)=>{
                        if (_exitcode == 0){
                            let size = File.getFileSize(`${PATH.MUSIC}/${res.fileName}`);
                            if (size < 300){
                                File.delete(`${PATH.MUSIC}/${res.fileName}`);
                                logger.info(`下载失败: ${res.fileName} | ${size}字节`);
                                mc.broadcast(`§c下载失败: ${res.fileName} | ${size}字节`);
                            }else{
                                logger.info(`下载完成: ${PATH.MUSIC}/${res.fileName} | ${(size/1024/1024).toFixed(2)}MB`);
                                mc.broadcast(`§a下载完成: ${res.fileName} | ${(size/1024/1024).toFixed(2)}MB`);
                            }
                            return;
                        }else{
                            mc.broadcast(`§c下载失败:\n${_output}`);
                            logger.error(`下载失败:\n${_output}`);
                            return;
                        }
                    }, 120000);
                    out.success(`开始下载 ${res.fileName}`);
                    return;
                case 'debug':
                    if (!(pl == null || pl.isOP() == true)){
                        out.error('此命令仅管理员可执行');
                        return;
                    }
                    if (res.debugMode == true){
                        logger.setConsole(true, 5); 
                        out.success('LF_Music Debug模式开启');
                    }else{
                        logger.setConsole(true, 4); 
                        out.success('LF_Music Debug模式关闭');
                    }
                    return;
            }

            if (pl == null){
                out.error("此命令的执行者须为玩家");
                return;
            }
            usrGUI(pl.xuid);
        });
        guicmd.setup();
    }
}


// 唱片菜单
var tmp = {};
var disc = ['minecraft:music_disc_11','minecraft:music_disc_13','minecraft:music_disc_blocks','minecraft:music_disc_cat','minecraft:music_disc_chirp','minecraft:music_disc_far',"minecraft:music_disc_mall","minecraft:music_disc_mellohi","minecraft:music_disc_otherside","minecraft:music_disc_pigstep","minecraft:music_disc_stal","minecraft:music_disc_strad","minecraft:music_disc_wait","minecraft:music_disc_ward","minecraft:music_disc_5"];


if (config.get('usrGUI')['enable'] == true){
    mc.listen("onUseItemOn",menu_send);
}
function menu_send(pl, item, block){
    //唱片点地触发菜单(防抖)
    let xuid = pl.xuid;
    if (!tmp[xuid]) {
        tmp[xuid] = true;
        setTimeout(function () {
            delete tmp[xuid];
        }, 300);

        if ((config.get('usrGUI')['itemGUI'] == "minecraft:music_disc" && disc.includes(item.type) && (block.type != 'minecraft:jukebox')) || item.type == config.get('usrGUI')['itemGUI'] ){
            usrGUI(pl.xuid);
        }
        
    }
}


// 添加音乐
function refMusic() {
    // 重新读取config.json
    config = new JsonConfigFile(PATH.MAIN + "/config.json");

    //检测音频，使用ffmpeg转换格式
    if (checkAudioFormat() == true){
        //mc.broadcast("[LF_Music] §e请等待格式转换, 完成后再次执行此命令");
        colorLog("yellow", "[ffmpeg] 请耐心等待音频转换完成");
        return false;
    }

    // 复制音乐文件到资源包 以及 FFmpeg 音频格式转换
    const musicArry = copyFL(PATH.MUSIC, config.get("serverRES") + "sounds/music/", config.get("sounds")["postfix"]);//导入音乐到资源包

    

    // 若导入音乐失败（文件命名问题）
    if (musicArry == false){ 
        return false;
    }

    // 重写资源包音乐定义属性
    writeRandD(musicArry, config.get("serverRES") + 'sounds/sound_definitions.json'); 
    DataArry = DataCfg.get("music");

    // 增加版本号
    if (updateVerion(config.get('serverRES') + 'manifest.json', config) == true) { 
        colorLog("yellow", `资源包版本:${PackVersion} -> ${config.get('version')}`);
    }

    // FFmpeg 正在获取音乐时长
    getMusicDuration();



    // 复制音乐文件到资源包
    function copyFL(from, to, postfix) {
        //需要config json对象

        let fileArry = File.getFilesList(from);
        let outArry = [];
       
        //清除所有旧音乐文件
        if (File.exists(to)){
            File.delete(to);
        }else{
            logger.error(`未找到 ${config.get("serverRES")}sounds/music/ 文件夹, 请检查资源包完整性, 或新建一个music文件夹`);
            return false;
        }
        
        //防止未输入后缀格式
        if (postfix.length == 0) {
            postfix = ["ogg"];
        }

        //创建资源包music目录
        File.mkdir(to);


        // 文件列表循环
        for (let i = 0; i < fileArry.length; i++) {
            // 音乐后缀名循环
            for (let v = 0; v < postfix.length; v++) {

                //let reg = new RegExp("(." + postfix[v] + ")$", "g");
                let reg = /^.*\.([A-Za-z]+)$/;
                var fl_postfix;
                
                if (reg.test(fileArry[i]) == true){
                    fl_postfix = reg.exec(fileArry[i])[1].toLowerCase(); //该文件后缀名
                }else{
                    fl_postfix = "";

                }
                

                // .ogg后缀判断
                if (fl_postfix == postfix[v]) {

                    if (File.copy(`${from}/${fileArry[i]}`, to) == true) {

                        // 判断音乐文件名是否是字母数字下划线
                        let filename_reg = /^\w+\.ogg$/;
                        if (filename_reg.test(fileArry[i]) == false){
                            logger.error(`音乐 ${fileArry[i]} 导入失败：文件名须为字母数字下划线`);
                            //mc.broadcast(`[LF_Muisc] §c导入音乐失败: ${fileArry[i]} 文件名须为字母数字下划线`);
                            continue;
                        }

                        //去除后缀
                        let reg = new RegExp("(." + postfix[v] + ")$", "i");
                        outArry.push(fileArry[i].replace(reg, ""));


                        //未设置debug显示
                        logger.info(`音乐 ${fileArry[i]} 导入成功`);
                    } else {
                        logger.info(`音乐 ${fileArry[i]} 导入复制音乐到资源包失败`);
                    }
                } else{
                    //log("检测到非ogg格式");
                }
            }

        }

        return outArry;
        //[musicName, musicName]
    }

    // 写入addons的音乐索引 以及 更新音乐信息(data.json) 
    function writeRandD(arry, pathR) {

        //需要config Data json对象
        const soundCfg = new JsonConfigFile(pathR, '{}');
     

        let newDataArry = {};
        DataCfg.reload();
        DataArry = DataCfg.get("music");

        let soundJson = {
            format_version: "1.14.0",
            sound_definitions: {
            }
        };

        // arry：所有要加入的歌曲 musicName列表
        for (let i = 0; i < arry.length; i++) {

            // record. 3D环绕的定义
            soundJson["sound_definitions"]["record."+ arry[i]] = {   
                category: "record",
                max_distance : 128,
                sounds: [
                    {
                        load_on_low_memory : true,
                        name: "sounds/music/" + arry[i],
                        stream: config.get("sounds")["stream"]
                    }
                ]
            };

            // music. bgm背景音乐的定义
            soundJson["sound_definitions"]["music.game." + arry[i]] = {  
                category: "music",
                sounds: [
                    {
                        name: "sounds/music/" + arry[i],
                        stream: config.get("sounds")["stream"]
                    }
                ]
            };

            // **更新歌曲信息
            // 已有的歌曲信息直接对应写入
            var getOldInfo = false;
            for (let key in DataArry) {
                if (key == arry[i]){
                    newDataArry[arry[i]] = {
                        rename: DataArry[key].rename,
                        author: DataArry[key].author,
                        hide: DataArry[key].hide != undefined ? DataArry[key].hide : false,
                        duration: DataArry[key].duration
                    };
                    getOldInfo = true;
                    break;
                }
            }
            // 新的歌曲信息写入
            if (getOldInfo == false){
                newDataArry[arry[i]] = {
                    rename: arry[i],
                    author: "",
                    hide: false,
                    duration: null
                };
            }

        }


        //更新全局变量
        soundCfg.write(data.toJson(soundJson, 1));
        DataCfg.set("music", newDataArry);

        DataCfg.reload();
        soundCfg.close();

    }

    //更新插件verion 和 addons verion
    function updateVerion(path) {
        //需要config json对象
        
        //Main 为addons  manifest
        let Main = new JsonConfigFile(path);
        let world = new JsonConfigFile(config.get('worldJson'), "[]");
        let worldJson = data.parseJson(world.read());
        
        let packuuid = config.get("PackUUID");
        if (packuuid != PackUUID){
            logger.info(`\n>>> 资源包uuid变更:\n [旧uuid]: ${PackUUID}\n [新uuid]: ${packuuid}\n [提示]: 你可以考虑删除${config.get('worldJson')}中的旧uuid`);
        }
        let version = PackVersion.slice(); // 当前运行的资源包版本，浅复制数组

        if (version[0] == null || version[1] == null || version[2] == null) {
            version = [0, 0, 1];
        } else if (version[0] >= 9 && version[1] >= 9 && version[2] >= 9) {
            logger.info('版本已达最大上限请修改uuid或想其他办法更新addons版本');
            return false;
        }

        // for (let i = 2; i > 0; i--) {
        //     if (version[i] <= 99) {
        //         version[i] += 1
        //         break
        //     } else {
        //         version[i] -= 99
        //         version[i - 1] += 1
        //     }
        // } 写法有误

        if (version[2] <= 9) {
            version[2] += 1;
        } else if (version[1] <= 9) {
            version[2] = 0;
            version[1] += 1;
        } else if (version[0] <= 9) {
            version[2] = 0;
            version[1] = 0;
            version[0] += 1;
        }


        Main.set('header', {
            description: "lxl加载器的lightSM的音乐资源包",
            name: "lightServerMusic",
            uuid: packuuid,
            version: version,
            min_engine_version: [
                1,
                14,
                0
            ]
        });

        Main.set("modules", [
            {
                description: "音乐资源包",
                type: "resources",
                uuid: "df2767fb-5bc1-41eb-b38d-2293eac94c92",
                version: version
            }
        ]);

        Main.close();


        // 更新 world_resource_packs.json
        if (worldJson.length == 0) {
            worldJson = [
                {
                    pack_id: packuuid,
                    version: version
                }
            ];

        } else {
    
            for (let i = 0; i < worldJson.length; i++) {

                // 升级音乐资源包版本
                if (worldJson[i]['pack_id'] == packuuid) {
                    worldJson[i]['version'] = version;
                    break;
                }

                // 循环结束，未找到该资源包uuid则创建新uuid
                if (i >= (worldJson.length - 1)) {
                    worldJson[worldJson.length] = {
                        pack_id: packuuid,
                        version: version
                    };
                    break;
                } 
            }
        }


        world.write(data.toJson(worldJson, 1));
        world.reload();
        world.close();

        config.set('version', version);
        config.reload();
        return true;
    }
}



// GUI菜单
function usrGUI(xuid) {
    let pl = mc.getPlayer(xuid);

    // 菜单功能函数列表（与菜单项目顺序匹配）
    var main_funList = [];

    // 菜单功能函数
    var main_funs = {
        // 播放音乐盒
        playBox(pl){
            var musicList_menu = mc.newSimpleForm();
            musicList_menu = selectmusic(musicList_menu); // 设置菜单音乐列表
            pl.sendForm(musicList_menu, function(pl, id){
                if (id == null) {return '菜单已放弃';}
                var musicName = Object.keys(DataArry).filter(info=>!DataArry[info].hide)[id];

                let CF = mc.newCustomForm();
                CF = CF.setTitle("♫ 音乐盒3D播放属性");
                //CF = CF.addLabel(`§9选择音乐 §f${DataArry[musicName]['rename']}\n\n §7请先停止当前BGM,否则BGM可能会重叠\n `);

                
                CF = CF.addLabel(`§9选择音乐 §f${DataArry[musicName]['rename']}\n `);
                
                
                if (config.get("usrGUI")["maxRadius"] == -1){
                    CF = CF.addInput(`向半径内的玩家播放 (@a[r=?])`,`请输入半径`,"1");
                }else{
                    CF = CF.addInput(`向半径内的玩家播放 (@a[r=?] 最大为${config.get("usrGUI")["maxRadius"]})`,`请输入半径`,"30");
                }
                CF = CF.addSwitch("§a自动播放", PlayList[pl.xuid]?.isAutoPlay ?? false);
                CF = CF.addSlider("音量", 1, 100, 1, 50);
                CF = CF.addSwitch("添加到播放列表", false);
                CF = CF.addSlider("远处玩家音源音量", 0, 100, 1, 0);

                
                pl.sendForm(CF, CF_run);
                
                function CF_run(pl, Arry){
                    if (Arry != null) {
                        if (!(/(^[1-9]\d*$)/.test(Number(Arry[1])))){
                            menu_end(pl, "§c§lERROR","§cERROR 请输入正整数",CF, CF_run);
                            return;
                        }
                        let musicMcName = "record." + musicName;
                        let R = Number(Arry[1]);
                        if (config.get("usrGUI")["maxRadius"] != -1){
                            if (R > Number(config.get("usrGUI")["maxRadius"])){
                                menu_end(pl, "§c§lERROR",`§cERROR 超出最大半径: ${Number(config.get("usrGUI")["maxRadius"])}`,CF, CF_run);
                                return;
                            }
                        }
                        let volume = Arry[3] / 100;
                        let minimumVolume = Arry[5] / 100;
                        let xyz = {x:pl.blockPos.x, y:pl.blockPos.y, z:pl.blockPos.z};

                        // 播放音乐盒
                        // 添加音乐列表（不立即播放）
                        if (Arry[4] == true){
                            addPlayList(pl, "record", musicName, R, musicMcName, volume, minimumVolume, xyz);
                            return;
                        }else{
                            insPlayList(pl, "record", musicName, R, musicMcName, volume, minimumVolume, xyz, Arry[2]);
                            return;
                        }
     
                    }
                }

            });
        },

        // 播放BGM
        playBgm(pl){
            var musicList_menu = mc.newSimpleForm();
            musicList_menu = selectmusic(musicList_menu); // 设置菜单音乐列表
            pl.sendForm(musicList_menu, function(pl,id){
                if (id == null) {return '菜单已放弃';}
                var musicName = Object.keys(DataArry).filter(info=>!DataArry[info].hide)[id];
                let CF = mc.newCustomForm();
                CF = CF.setTitle("♫ BGM跟随播放属性");
                //CF = CF.addLabel(`§9选择音乐 §f${DataArry[musicName]['rename']}\n\n §7请先停止当前BGM,否则BGM可能会重叠\n `);
                CF = CF.addLabel(`§9选择音乐 §f${DataArry[musicName]['rename']}\n ${BGM_enabled ? "\n§r§7(可能与背景音乐重叠, 设置中可调低<音乐>的音量)" : ""}`);
                if (config.get("usrGUI")["maxRadius"] == -1){
                    CF = CF.addInput(`向半径内的玩家播放 (@a[r=?])`,`请输入半径`,"1");
                }else{
                    CF = CF.addInput(`向半径内的玩家播放 (@a[r=?] 最大为${config.get("usrGUI")["maxRadius"]})`,`请输入半径`,"1");
                }
                CF = CF.addSwitch("§a自动播放", PlayList[pl.xuid]?.isAutoPlay ?? false);
                CF = CF.addSlider("音量", 1, 100, 1, 15);
                CF = CF.addSwitch("添加到播放列表", false);
                if (config.get("usrGUI")["svrLoopPlay"] == true || pl.isOP() == true){
                    CF = CF.addSwitch("添加到全服背景音乐(单次)", false);
                }
                if (pl.isOP() && BGM_enabled){
                    CF = CF.addSwitch("§6添加到全服背景音乐(管理员)", false);
                }

                pl.sendForm(CF, CF_run);
                
                function CF_run(pl, Arry){
                    if (Arry != null) {
                        if (!(/(^[1-9]\d*$)/.test(Number(Arry[1])))){
                            menu_end(pl, "§c§lERROR","§cERROR 请输入正整数",CF, CF_run);
                            return;
                        }
                        let musicMcName = 'music.game.' + musicName;
                        let R = Number(Arry[1]);
                        if (config.get("usrGUI")["maxRadius"] != -1){
                            if (R > Number(config.get("usrGUI")["maxRadius"])){
                                menu_end(pl, "§c§lERROR",`§cERROR 超出最大半径: ${Number(config.get("usrGUI")["maxRadius"])}`,CF, CF_run);
                                return;
                            }
                        }
                        let volume = Arry[3] / 100;


                        // 全服播放 (/music)
                        if (Arry[5] == true){
                            if (BGM_enabled){
                                if (DataArry[musicName]["duration"] == -1 || DataArry[musicName]["duration"] == null){
                                    pl.tell(`§c未知音频时长, §r${DataArry[musicName]['rename']}§r§c 无法播放全服背景音乐`);
                                    return;
                                }
                                CurrentBGM.musicName = musicName;
                                CurrentBGM.endTime = new Date().getTime() + parseDuration(DataArry[musicName]["duration"]) + 3000;
                            }
                            mc.runcmdEx(`music play ${musicMcName} ${bgm_cfg.get("volume")} 2 play_once`);
                            mc.broadcast(`[LF_Music] §a<${pl.realName}> §6播放全服背景音乐——§r${DataArry[musicName]['rename']}`);
                            return;
                        }

                        // 添加全服播放
                        if (Arry[6] == true){
                            if (DataArry[musicName]["duration"] == -1 || DataArry[musicName]["duration"] == null){
                                pl.tell(`§c未知音频时长, §r${DataArry[musicName]['rename']}§r§c 无法添加到全服背景音乐`);
                                return;
                            }
                            let playList = bgm_cfg.get("playList");
                            if (playList.includes(musicName)){
                                mc.broadcast(`[LF_Music] ${DataArry[musicName]['rename']} §r§9已在全服背景音乐中`);
                                return;
                            }
                            playList.push(musicName);
                            bgm_cfg.set("playList", playList);
                            mc.broadcast(`[LF_Music] ${DataArry[musicName]['rename']} §r§9已添加到全服背景音乐`);
                            return;
                        }
                        //let xyz = {x:pl.blockPos.x, y:pl.blockPos.y, z:pl.blockPos.z};

                        // 播放并添加音乐列表（不立即播放）
                        if (Arry[4] == true){
                            addPlayList(pl, "bgm", musicName, R, musicMcName, volume, undefined, undefined);
                            return;
                        }else{
                            insPlayList(pl, "bgm", musicName, R, musicMcName, volume, undefined, undefined, Arry[2]);
                            return;
                        }

                    }
                }

            });
        },

        // 停止播放
        stopMusic(pl){
            if (pl.xuid in PlayList){
                PlayList[pl.xuid]["mode"] = undefined;
                PlayList[pl.xuid]["endTime"] = undefined;
                PlayList[pl.xuid]["xyz"] = undefined;
                PlayList[pl.xuid]["R"] = undefined;
                PlayList[pl.xuid]["volume"] = undefined;
                PlayList[pl.xuid]["minimumVolume"] = undefined;
            }
            mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run stopsound @s`);
            LRCremove(pl, "right");
            pl.sendText(`[LF_Music] §7已停止单人BGM`);
        },

        // 下一首
        nextMusic(pl){
            PlayList[pl.xuid]["musicList"].push(PlayList[pl.xuid]["musicList"].shift());
            let musicName = PlayList[pl.xuid]["musicList"][0]; 
            PlayList[pl.xuid]["endTime"] = new Date().getTime() + parseDuration(DataArry[musicName]["duration"]);

            debugPlaylist();
            
            //播放下一首音乐
            if (PlayList[pl.xuid]["xyz"] == undefined){
                playMusic(pl, "bgm", musicName, PlayList[pl.xuid].R, `music.game.${musicName}`, PlayList[pl.xuid].volume, PlayList[pl.xuid].minimumVolume);
            }else{
                playMusic(pl, "record", musicName, PlayList[pl.xuid].R, `record.${musicName}`, PlayList[pl.xuid].volume, PlayList[pl.xuid].minimumVolume, PlayList[pl.xuid]["xyz"]);
            }
        },

        // 播放顺序循环模式
        loopMode(pl){
            switch(PlayList[pl.xuid]["playOrder"]){
                case "Loop":
                    PlayList[pl.xuid]["playOrder"] = "ListLoop";break;
                case "ListLoop":
                    // 除第一项打乱列表
                    var tempList = PlayList[pl.xuid]["musicList"].slice(1);
                    tempList = shuffle(tempList);
                    tempList.unshift(PlayList[pl.xuid]["musicList"][0]);
                    PlayList[pl.xuid]["musicList"] = tempList;

                    PlayList[pl.xuid]["playOrder"] = "Random";break;
                case "Random":
                    PlayList[pl.xuid]["playOrder"] = "Loop";break;
                default:
                    PlayList[pl.xuid]["playOrder"] = "ListLoop";
            }
            pl.sendForm(main_menu_set(pl), main_run);
        },

        // 播放列表
        musicList(pl){
            // 菜单构建
            function menu_playList_set(pl){
                //检查与滤除当前播放列表
                CheckPlayList(pl.xuid);

                let menu_playList = mc.newCustomForm();
                menu_playList.setTitle("§l≡ 播放列表");

                // 构建当前播放列表
                let pl_playList = "";
                if (PlayList[pl.xuid] == undefined){
                    pl_playList += "\n§c当前播放列表为空\n";
                }else{

                    let musicReName = DataArry[PlayList[pl.xuid]["musicList"][0]]["rename"];
                    
                    // 当前播放
                    if (PlayList[pl.xuid]["xyz"] != undefined){
                        pl_playList += `\n${PlayList[pl.xuid].endTime? '§9播放中': '§3暂停'}: §r${musicReName}\n§r§7当前音乐盒地点: ${PlayList[pl.xuid]["xyz"].x}, ${PlayList[pl.xuid]["xyz"].y}, ${PlayList[pl.xuid]["xyz"].z}\n`;
                    }else{
                        pl_playList += `\n${PlayList[pl.xuid].endTime? '§9播放中': '§3暂停'}: §r${musicReName}\n`;
                    }
                    
                    // 当前播放列表
                    for (let i=0; i<PlayList[pl.xuid]["musicList"].length; i++){
                        let musicName = PlayList[pl.xuid]["musicList"][i];                 
                            pl_playList +=`\n§d# ${i+1} | §r${DataArry[musicName]["rename"]}`;
                        
                            if (DataArry[musicName]["author"] != null && DataArry[musicName]["author"] != ""){
                            pl_playList += `§r§7 - ${DataArry[musicName]["author"]}`;
                            }
                            if (DataArry[musicName]["duration"] != null && DataArry[musicName]["duration"] != -1){
                                pl_playList += `  §r§7[${StringSecend(parseDuration(DataArry[musicName]["duration"])/1000)}]`;
                            }                
                    }
                }

                pl_playList += "\n§7==============================";
                
                menu_playList.addLabel(pl_playList);
                menu_playList.addSwitch("§a自动播放", PlayList[pl.xuid]?.isAutoPlay ?? false); 
                if (PlayList[pl.xuid]  == undefined){
                    menu_playList.addSwitch("保存当前播放列表§7 （不可用）",false);
                }else{
                    menu_playList.addSwitch("保存当前播放列表", false);
                }
                
                if (musicList_config.get(pl.xuid) == null){
                    menu_playList.addSwitch(`载入播放列表§7 （无保存的列表）`,false);
                }else if(musicList_config.get(pl.xuid)["savedList"] == undefined){
                    menu_playList.addSwitch(`载入播放列表§7 （无保存的列表）`,false);
                }else{
                    menu_playList.addSwitch(`载入播放列表§7 （${musicList_config.get(pl.xuid)["logTime"]}）`,false);
                }
                
                menu_playList.addInput("§c从列表中移除某个音乐(输入序号)","请输入序号");
                menu_playList.addSwitch("§c清空播放列表",false);
                return menu_playList;
            }

            //菜单处理
            function playList_run(pl, args){
                if (args == null){return;}
                let autoPlay = args[1];
                let saveList = args[2];
                let loadList = args[3];
                let removeMusic = args[4];
                let emptyList = args[5];

                if (PlayList[pl.xuid] != null){
                    if (autoPlay != PlayList[pl.xuid]["isAutoPlay"]){
                        PlayList[pl.xuid]["isAutoPlay"] = autoPlay;
                    }
                }

                // 保存播放列表
                if (saveList == true){
                    if (PlayList[pl.xuid]  == undefined){
                        menu_end(pl, "§l≡ 播放列表",`§cERROR 当前列表为空，保存失败`, menu_playList_set(pl), playList_run);
                        return;
                    }

                    //该玩家没有保存过播放列表 musicList.config 
                    if (musicList_config.get(pl.xuid) == null){
                        let dataTemp = {
                            playName: pl.realName,
                            logTime: system.getTimeStr(), 
                            savedList: PlayList[pl.xuid]["musicList"],
                            lastList: PlayList[pl.xuid]["musicList"],
                            playOrder: PlayList[pl.xuid]["playOrder"]
                        };

                        if (musicList_config.set(pl.xuid, dataTemp)){
                            menu_end(pl, "§l≡ 播放列表",`§a当前播放列表保存成功！`, menu_playList_set(pl), playList_run);
                            return;
                        }else{
                            menu_end(pl, "§l≡ 播放列表",`§cERROR 保存失败`, menu_playList_set(pl), playList_run);
                            return;
                        }
                    }else{
                    //该玩家已有保存的播放列表

                        let dataTemp = musicList_config.get(pl.xuid);
                        dataTemp["savedList"] = PlayList[pl.xuid]["musicList"];
                        dataTemp["logTime"] = system.getTimeStr();
                        dataTemp["playOrder"] = PlayList[pl.xuid]["playOrder"];

                        if (musicList_config.set(pl.xuid, dataTemp)){
                            menu_end(pl, "§l≡ 播放列表",`§a当前播放列表保存成功！`, menu_playList_set(pl), playList_run);
                            return;
                        }else{
                            menu_end(pl, "§l≡ 播放列表",`§cERROR 保存失败`, menu_playList_set(pl), playList_run);
                            return;
                        }
                    }   
                }

                // 载入播放列表
                if (loadList == true){

                    // 该玩家没有保存过播放列表
                    if (musicList_config.get(pl.xuid) == null){
                        menu_end(pl, "§2§l播放列表",`§cERROR 你没有保存过播放列表`, menu_playList_set(pl), playList_run);
                        return;
                    }else if(musicList_config.get(pl.xuid)["savedList"] == undefined){
                        menu_end(pl, "§2§l播放列表",`§cERROR 你没有保存过播放列表`, menu_playList_set(pl), playList_run);
                        return;
                    }else{
                    // 该玩家有保存的播放列表
                        // 当前播放列表初始化与载入
                        if (pl.xuid in PlayList){
                            PlayList[pl.xuid]["musicList"] = musicList_config.get(pl.xuid)["savedList"];
                            PlayList[pl.xuid]["playOrder"] = musicList_config.get(pl.xuid)["playOrder"];
                        }else{
                            PlayList[pl.xuid] = {
                                playName: pl.realName,
                                musicList: musicList_config.get(pl.xuid)["savedList"],
                                playOrder: musicList_config.get(pl.xuid)["playOrder"],// 默认列表循环
                            };
                        }

                        //检查载入的播放列表
                        CheckPlayList(pl.xuid);
                        pl.sendForm(menu_playList_set(pl), playList_run);
                        return;
                    }
                }

                // 从列表移除某个音乐
                if (removeMusic != ""){
                    if (PlayList[pl.xuid]  == undefined){
                        menu_end(pl, "§2§l播放列表",`§cERROR 当前列表为空`, menu_playList_set(pl), playList_run);
                        return;
                    }
                    if (!(/(^[1-9]\d*$)/.test(removeMusic))){
                        menu_end(pl, "§c§l播放列表","§cERROR 请输入正整数", menu_playList_set(pl), playList_run);
                        return;
                    }

                    if (Number(removeMusic) > PlayList[pl.xuid]["musicList"].length){
                        menu_end(pl, "§c§l播放列表","§cERROR 没有此序号对应的音乐", menu_playList_set(pl), playList_run);
                        return;
                    }


                    let musicName = DataArry[PlayList[pl.xuid]["musicList"][Number(removeMusic)-1]]["rename"];
                    PlayList[pl.xuid]["musicList"].splice(Number(removeMusic)-1, 1);
                    if (PlayList[pl.xuid]["musicList"].length == 0){ //如果列表为空
                        delete PlayList[pl.xuid]; 
                    }
                    menu_end(pl, "§2§l播放列表",`§a从播放列表中移除: §r${musicName}`, menu_playList_set(pl), playList_run);
                    return;
                }
                
                // 清空列表
                if (emptyList == true){
                    if (PlayList[pl.xuid]  == undefined){
                        menu_end(pl, "§2§l播放列表",`§cERROR §r当前列表已经为空`, menu_playList_set(pl), playList_run);
                        return;
                    }
                    delete PlayList[pl.xuid]; 
                    //PlayList[pl.xuid]["musicList"] = [];
                    menu_end(pl, "§2§l播放列表",`§c已清空播放列表`, menu_playList_set(pl), playList_run);
                    return;
                }

                // 无动作
                pl.sendForm(main_menu_set(pl), main_run);

                return;
            }
            pl.sendForm(menu_playList_set(pl), playList_run);
        },

        // 歌词显示
        lrcDisplay(pl){
            if (CurrentMusic[String(pl.xuid)] == undefined){
                pl.sendText("[LF_Music] §c当前没有播放音乐 或 该音乐没有歌词");
            }

            //关闭则开启
            if (CurrentMusic[String(pl.xuid)]["lrcSwitch"] == false){
                if (config.get('usrGUI').lrcDisplay == "Popup"){
                    pl.tell("§a请欣赏: §d"+ CurrentMusic[String(pl.xuid)]["musicRename"], 4);
                }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                    pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), "§a请欣赏: §d"+ CurrentMusic[String(pl.xuid)]["musicRename"], 100, 0);
                }
                CurrentMusic[String(pl.xuid)]["lrcSwitch"] = true;
            }else{ // 开启则关闭
                CurrentMusic[String(pl.xuid)]["lrcSwitch"] = false;
                pl.removeBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)));
            }
        },

        // 停止循环播放
        stopLoopMusic(pl){
            mc.broadcast(`[LF_Music] §a<${pl.realName}> §7已停止全服BGM`);
            mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run music stop 3`);
        },

        // 插件配置
        pluginConfig(pl){
            let usrGUI_conf = config.get("usrGUI");
            let config_menu = mc.newCustomForm();
            config_menu.setTitle("§c§lLF_Music 插件配置");
            config_menu.addInput("\n◆ 选择玩家播放的最大半径(-1为无穷远)(OP不受限制)", "请输入正整数或-1", String(usrGUI_conf.maxRadius));
            config_menu.addInput("◆ 召唤音乐菜单的物品", "请输入物品标准类型名", usrGUI_conf.itemGUI);
            config_menu.addSwitch(`§c◆ 去设置音乐信息和入服音乐\n §7(入服音乐: ${config.get("usrGUI")["playerJoinMusic"]})`, false);
            config_menu.addSwitch("◆ 是否允许玩家播放全服背景音乐\n §7(OP不受限制)", usrGUI_conf.svrLoopPlay);
            config_menu.addSwitch("§c◆ 去设置全服背景音乐", false);
            config_menu.addSwitch("◆ 歌词显示总开关", usrGUI_conf.lrc);
            config_menu.addSwitch("◆ 重新读取音频时长(FFmpeg)", false);
            

            pl.sendForm(config_menu, config_menu_run);

            function config_menu_run(pl, Arry){
                if (Arry == null) {return '菜单已放弃';}

                if (!(/(^[1-9]\d*$)/.test(Number(Arry[0]))) && Arry[0] != "-1"){
                    menu_end(pl, "§c§lERROR",`§cERROR 请输入正整数或-1`, config_menu, config_menu_run);
                    return;
                }


                if (Arry[3] != usrGUI_conf.svrLoopPlay){
                    usrGUI_conf.svrLoopPlay = Arry[3];
                    pl.sendText(`[LF_Music] 全服背景音乐播放开关: ${Arry[3]}`);
                    logger.info(`[LF_Music] 全服背景音乐播放开关: ${Arry[3]}`);
                }
                
                

                if (Number(Arry[0]) != usrGUI_conf.maxRadius){
                    usrGUI_conf.maxRadius = Number(Arry[0]);
                    pl.sendText(`[LF_Music] 最大播放半径: ${Arry[0]}`);
                    logger.info(`[LF_Music] 最大播放半径: ${Arry[0]}`);
                }

                if (Arry[1] != usrGUI_conf.itemGUI){
                    usrGUI_conf.itemGUI = Arry[1];
                    pl.sendText(`[LF_Music] 召唤音乐菜单的物品: ${Arry[1]}`);
                    logger.info(`[LF_Music] 召唤音乐菜单的物品: ${Arry[1]}`);
                }

                

                // 去设置每一首音乐
                if (Arry[2] == true){
                    var setMusic_menu = mc.newSimpleForm();
                    setMusic_menu = selectmusic(setMusic_menu, true);
                    pl.sendForm(setMusic_menu, setMusic_menu_run);
                    function setMusic_menu_run(pl, id){
                        if (id == null) {return pl.sendForm(config_menu, config_menu_run);}
                        var musicName = Object.keys(DataArry)[id];
                        let setInfo_menu = mc.newCustomForm();
                        setInfo_menu.setTitle("§c§l设置这首音乐");
                        setInfo_menu.addLabel(`§9选择音乐 §f${DataArry[musicName]['rename']}\n§r§7音乐文件名: ${musicName}\n `);

                        // 音乐信息 (Arry[1],Arry[2])
                        let author = DataArry[musicName]['author'];
                        if (author == undefined || author == ""){
                            author = "";
                        }
                        setInfo_menu.addInput("§c(管理员) §r歌曲重命名", "请输入该音乐的新名称(可以为中文)", DataArry[musicName]['rename']);
                        setInfo_menu.addInput("§c(管理员) §r歌曲作者", "请输入歌曲作者", author);
                        setInfo_menu.addSwitch("§6隐藏该音乐", DataArry[musicName].hide != undefined ? DataArry[musicName].hide : false);

                        // 入服音乐 (Arry[3])
                        let usrGUI_conf = config.get("usrGUI");
                        if (musicName == usrGUI_conf["playerJoinMusic"]){
                            setInfo_menu.addSwitch("§b设置为入服音乐", true);
                        }else{
                            setInfo_menu.addSwitch(`§b设置为入服音乐§7 (当前音乐: ${usrGUI_conf["playerJoinMusic"]})`, false);
                        }

                        // 歌词偏移输入框 (Arry[4])
                        if (File.exists(`${PATH.MUSIC}/${musicName}.lrc`)){

                            let lrc = File.readFrom(`${PATH.MUSIC}/${musicName}.lrc`);
                            var lrcList1 = lrc.split("\n");
                            var biasReg = /歌词偏移\s*=\s*((\-|\+)?\d+)/;
                            var customBias = 0;
                            for (let i = 0; i<lrcList1.length; i++){
                                if (biasReg.test(lrcList1[i]) == true){
                                    customBias = Number(biasReg.exec(lrcList1[i])[1]);
                                }
                            }
                            setInfo_menu.addInput("歌词偏移(毫秒)(正数为歌词延迟显示)", "输入偏移量(整数)", String(customBias));
                        }

                        pl.sendForm(setInfo_menu, setInfo_menu_run);

                        function setInfo_menu_run(pl, Arry){
                            if (Arry == null) {return '菜单已放弃';}
                            let result = "";
                            // 管理员更新音乐信息
                            let author = DataArry[musicName]['author'];
                            if (author == undefined || author == ""){
                                author = "";
                            }
                            if (Arry[1] !=  DataArry[musicName]['rename'] || Arry[2] != author){
                                if (Arry[1] == ""){
                                    Arry[1] = musicName;
                                    DataArry[musicName]['rename'] = Arry[1];
                                    
                                }
                                result = result + `§c<${pl.realName}> §b更新音乐信息: \n§r§b歌曲: §r${DataArry[musicName]['rename']} §e—> §r${Arry[1]}\n§r§b作者: §r${author} §e—> §r${Arry[2]}`;                   
                                DataArry[musicName]['rename'] = Arry[1];
                                DataArry[musicName]['author'] = Arry[2];
                                DataCfg.set("music", DataArry);
                            }
                            
                            if (Arry[3] != DataArry[musicName]['hide']){
                                DataArry[musicName]['hide'] = Arry[3];
                                DataCfg.set("music", DataArry);
                            }
                            
                            // 设置入服音乐
                            if (musicName == usrGUI_conf["playerJoinMusic"]){
                                if (Arry[4] == false){
                                    // 取消入服音乐
                                    result = result + `\n\n§c取消入服音乐: §r${DataArry[musicName]["rename"]}`;
                                    usrGUI_conf["playerJoinMusic"] = "无";
                                    config.set("usrGUI", usrGUI_conf);
                                }
                            }else{
                                if (Arry[4] == true){
                                    result = result + `\n\n§a设置入服音乐: §r${DataArry[musicName]["rename"]}`;
                                    usrGUI_conf["playerJoinMusic"] = musicName;
                                    config.set("usrGUI", usrGUI_conf);
                                }
                            }

                            // 设置歌词偏移
                            
                            if (Arry[5] != String(customBias) && Arry[5] != undefined){
                                if (!(/^(\-|\+)?\d+$/.test(Arry[5])) && Arry[5] != ""){
                                    menu_end(pl,"§c§l设置歌词偏移" , "ERROR 请输入整数", setMusic_menu, setMusic_menu_run);
                                    return;
                                }
                                
                                if (Arry[5] == ""){
                                    Arry[5] = "0";
                                }

                                // 更新歌词行列表
                                let updata = false;
                                for (let i = 0; i<lrcList1.length; i++){
                                    if (biasReg.test(lrcList1[i]) == true){
                                        lrcList1[i] = `歌词偏移 = ${Arry[5]}`;
                                        updata = true;
                                    }
                                }
                                if (updata == false){
                                    lrcList1.unshift(`歌词偏移 = ${Arry[5]}`);
                                }

                                // 读入歌词文件到内存
                                if (LRCdata[musicName] == undefined){
                                    LRCdata[musicName] = LRCparse(musicName);
                                }
                                // 更新歌词内存中的偏移
                                LRCdata[musicName][2] = Number(Arry[5]);

                                // 重组歌词文件内容，更新写入歌词文件
                                File.writeTo(`${PATH.MUSIC}/${musicName}.lrc`,lrcList1.join("\n"));

                                result = result + `\n\n§a设置歌词偏移 ${Arry[5]}`;
                            
                                
                            }


                            // 显示执行结果
                            if (result != ""){
                                menu_end(pl,"§c§l设置这首音乐" , result, setMusic_menu, setMusic_menu_run);
                            }else{
                                pl.sendForm(setMusic_menu, setMusic_menu_run);
                            }
                            
                            return;
                        }

                        
                    }
                    return;
                }

                // 去设置全服背景音乐
                if (Arry[4] == true){
                    let fm_BGM = mc.newCustomForm();
                    fm_BGM.setTitle("§c全服背景音乐");
                    let playListStr = '\n §b当前背景音乐:';
                    let playList = bgm_cfg.get("playList");
                    for (let i=0; i<playList.length; i++){
                        playListStr += `\n§6# ${i+1}| §r${DataArry[playList[i]].rename} - §7${DataArry[playList[i]].author}`;
                    }
                    fm_BGM.addLabel(playListStr);
                    fm_BGM.addSwitch("开启自定义全服背景音乐", bgm_cfg.get("enabled") ? true : false);
                    fm_BGM.addSlider("§6背景音量", 0, 100, 1, bgm_cfg.get("volume") * 100);
                    fm_BGM.addInput("§e随机间隔时间(秒)(最短)", "请输入正整数", String(bgm_cfg.get("minRandomInterval")));
                    fm_BGM.addInput("§e随机间隔时间(秒)(最长)", "请输入正整数", String(bgm_cfg.get("maxRandomInterval")));
                    fm_BGM.addInput("§c从列表中移除某个音乐", "请输入音乐序号");
                    pl.sendForm(fm_BGM, BGM_run);
                    function BGM_run(pl, args){
                        if (args == null){return pl.sendForm(config_menu, config_menu_run);}
                        let enabled = args[1];
                        let volume = args[2];
                        let minRandomInterval = args[3];
                        let maxRandomInterval = args[4];
                        let deleteIndex = args[5];
                        if (enabled != bgm_cfg.get("enabled")){
                            bgm_cfg.set("enabled", enabled);
                            BGM_enabled = enabled;
                            return menu_end(pl, "§c全服背景音乐", `§a已 ${enabled ? "开启" : "§c关闭"} §a全服背景音乐`, config_menu, config_menu_run);
                        }
                        if (volume/100 != bgm_cfg.get("volume")){
                            bgm_cfg.set("volume", volume/100);
                            return menu_end(pl, "§c全服背景音乐", `§a已调整音量为 ${volume/100}`, config_menu, config_menu_run);
                        }
                        if (Number(minRandomInterval) != bgm_cfg.get("minRandomInterval") || Number(maxRandomInterval) != bgm_cfg.get("maxRandomInterval")){
                            if (!(/(^[1-9]\d*$)/.test(minRandomInterval))){
                                return menu_end(pl, "§c全服背景音乐",`§cERROR 请输入正整数`, fm_BGM, BGM_run);
                            }
                            if (!(/(^[1-9]\d*$)/.test(maxRandomInterval))){
                                return menu_end(pl, "§c全服背景音乐",`§cERROR 请输入正整数`, fm_BGM, BGM_run);
                            }
                            minRandomInterval = Number(minRandomInterval);
                            maxRandomInterval = Number(maxRandomInterval);
                            if (minRandomInterval > maxRandomInterval){
                                return menu_end(pl, "§c全服背景音乐",`§cERROR 最短时间应小于最长时间`, fm_BGM, BGM_run);
                            }
                            bgm_cfg.set("minRandomInterval", minRandomInterval);
                            bgm_cfg.set("maxRandomInterval", maxRandomInterval);
                            return menu_end(pl, "§c全服背景音乐",`§6已重设随机间隔时间: ${minRandomInterval} - ${maxRandomInterval}`, config_menu, config_menu_run);
                        }
                        if (deleteIndex != ""){
                            if (!(/(^[1-9]\d*$)/.test(deleteIndex))){
                                return menu_end(pl, "§c全服背景音乐",`§cERROR 请输入正整数`, fm_BGM, BGM_run);
                            }
                            if (Number(deleteIndex) > playList.length){
                                return menu_end(pl, "§c全服背景音乐",`§cERROR 没有此序号对应的音乐`, fm_BGM, BGM_run);
                            }
                            deleteIndex = Number(deleteIndex) - 1;
                            let deleteName = playList[deleteIndex];
                            cache_BGMlist.splice(cache_BGMlist.indexOf(deleteName));
                            playList.splice(deleteIndex, 1);
                            bgm_cfg.set("playList", playList);
                            return menu_end(pl, "§c全服背景音乐",`§6已从全服BGM中移除§r ${DataArry[deleteName].rename}`, config_menu, config_menu_run);
                        }
                        return pl.sendForm(config_menu, config_menu_run);
                    }
                    return;
                }

                // 歌词显示总开关
                if (Arry[5] != usrGUI_conf.lrc){
                    usrGUI_conf.lrc = Arry[5];
                    pl.sendText(`[LF_Music] 歌词显示: ${Arry[5]}`);
                    logger.info(`[LF_Music] 歌词显示: ${Arry[5]}`);
                }

                // FFmpeg 重读音频时长
                if (Arry[6] == true){
                    getMusicDuration();
                }
                config.set("usrGUI", usrGUI_conf);

                return;
            }
        }

    };


    // 主菜单构建
    function main_menu_set(pl){

        main_funList = [];
        let main_menu = mc.newSimpleForm();
        main_menu = main_menu.setTitle('§l§c♫ 音乐主菜单 ♫');
        if (pl.xuid in PlayList){
            if (PlayList[pl.xuid]["endTime"] != undefined){
                main_menu = main_menu.setContent(`\n §b“时间诉说，细细聆听”： §r${DataArry[PlayList[pl.xuid]["musicList"][0]]["rename"]}  \n `);
            }else{
                main_menu = main_menu.setContent(`\n  §b" 放慢脚步，沉醉于这悠扬的旋律中吧~ "\n `);
            }
        }else{
            main_menu = main_menu.setContent(`\n  §b" 放慢脚步，沉醉于这悠扬的旋律中吧~ "\n `);
        }
        
        main_menu = main_menu.addButton('§2§l▶ 播放音乐盒');main_funList.push(main_funs.playBox);
        main_menu = main_menu.addButton('§3§l▶ 播放BGM'); main_funList.push(main_funs.playBgm);
        
        if (pl.xuid in PlayList){
            if (PlayList[pl.xuid]["endTime"] != undefined){
                main_menu = main_menu.addButton('§l✈ 下一首'); main_funList.push(main_funs.nextMusic);

                switch (PlayList[pl.xuid]["playOrder"]){
                    case "Loop":
                        main_menu = main_menu.addButton('§l∞ 播放顺序： 单曲循环');main_funList.push(main_funs.loopMode);break;
                    case "ListLoop":
                        main_menu = main_menu.addButton('§l∞ 播放顺序： 列表循环');main_funList.push(main_funs.loopMode);break;
                    case "Random":
                        main_menu = main_menu.addButton('§l∞ 播放顺序： 随机播放');main_funList.push(main_funs.loopMode);break;
                }

                
            }
        }

        main_menu = main_menu.addButton('§l≡ 播放列表');main_funList.push(main_funs.musicList);
        
        if (CurrentMusic[pl.xuid] == undefined || config.get("usrGUI")["lrc"] == false){
            //不显示歌词按钮
            //main_menu = main_menu.addButton('§l▶ 显示歌词');
        }else{
            if (CurrentMusic[pl.xuid]["lrcSwitch"] == false){
                main_menu = main_menu.addButton('§l▶ 显示歌词');main_funList.push(main_funs.lrcDisplay);
            }else{
                main_menu = main_menu.addButton('§l■ 隐藏歌词'); main_funList.push(main_funs.lrcDisplay);
            }

        }

        main_menu = main_menu.addButton('§l■ 停止单人播放'); main_funList.push(main_funs.stopMusic);

        // if (config.get("usrGUI")["svrLoopPlay"] == true || pl.isOP() == true){
        //     main_menu = main_menu.addButton('§l■ 停止全服背景音乐');main_funList.push(main_funs.stopLoopMusic);
        // }

        if (pl.isOP() == true){
            main_menu = main_menu.addButton('§c§l● 插件配置');main_funList.push(main_funs.pluginConfig);
        }
        return main_menu;
    }


    // 主菜单处理
    function main_run(pl, id){
        if (id == null) {return;}

        //执行选项对应功能
        main_funList[id](pl);

    }

    // 发送主菜单
    pl.sendForm(main_menu_set(pl), main_run);
}



// 进服监听
mc.listen("onJoin", function (pl){
    // 入服音乐
    if (config.get("usrGUI")["playerJoinMusic"] != "无"){
        mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run playsound music.game.${config.get("usrGUI")["playerJoinMusic"]} @s ~~~ ${((config.get("usrGUI")["playerJoinMusicVolume"] ?? 20) /100).toFixed(2)}`);// 入服音量:20
    }
    // 进服载入上次播放列表
    if (musicList_config.get(pl.xuid) != null){
        let dataTemp = musicList_config.get(pl.xuid);
        if (dataTemp["lastList"] != undefined){
            // 当前播放列表初始化与载入
            if (!(pl.xuid in PlayList)){
                PlayList[pl.xuid] = {
                    playName: pl.realName,
                    musicList: dataTemp["lastList"] ?? [],
                    playOrder: dataTemp["playOrder"] ?? "ListLoop",// 默认列表循环
                    isAutoPlay: dataTemp["isAutoPlay"] ?? false
                };
                //检查与滤除载入的播放列表
                CheckPlayList(pl.xuid);
            }
        }
    }
});

// 离线监听
mc.listen("onLeft", function(pl){
    // 离服自动缓存当前播放列表（保存 播放列表 与 播放顺序）
    if (pl.xuid in PlayList){
        //播放列表config是否初始化
        if (musicList_config.get(pl.xuid) == null){
            let dataTemp = {
                playName: pl.realName,
                lastList: PlayList[pl.xuid]["musicList"],
                playOrder: PlayList[pl.xuid]["playOrder"],
                isAutoPlay: PlayList[pl.xuid]["isAutoPlay"]
            };
            musicList_config.set(pl.xuid, dataTemp);
        }else{
            let dataTemp = musicList_config.get(pl.xuid);
            dataTemp["lastList"] = PlayList[pl.xuid]["musicList"];
            dataTemp["playOrder"] = PlayList[pl.xuid]["playOrder"];
            dataTemp["isAutoPlay"] = PlayList[pl.xuid]["isAutoPlay"];
            musicList_config.set(pl.xuid, dataTemp);
        }
        //离线删除该玩家的播放列表队列
        delete PlayList[pl.xuid];
    }

    // 离线删除歌词显示队列
    if (CurrentMusic[pl.xuid] != undefined){
        delete CurrentMusic[pl.xuid];
    }

});


//============================================================================================================================
//============================================================================================================================
//============================================================================================================================
// Funtion
// 表单构建函数——所有音乐列表
function selectmusic(menu, displayHide = false){
    menu = menu.setTitle("§c§l♫ 选择音乐");
    menu = menu.setContent("§l选一首喜欢的音乐吧~\n ");

    // 重新读取歌曲
    // DataCfg.reload();
    // DataArry = DataCfg.get("music");
    var i = 0;
    for (let musicName in DataArry){
        if (!displayHide){
            if (DataArry[musicName].hide === true){continue;} // 跳过隐藏
        }
        i++;
        let rename = DataArry[musicName]["rename"];
        let author = DataArry[musicName]["author"];
        let duration = DataArry[musicName]["duration"];
  


        let textFormat = config.get("usrGUI")["defaultTEXT"];
        let content = "";

        if (rename == "") {
            rename = musicName;
        }

        if (typeof (DataArry[musicName]["text"]) == "string" && DataArry[musicName]["text"] != "") {
            textFormat = DataArry[musicName]["text"];
        }
        //content = format(textFormat, { name: rename });
        content = textFormat.replace('{musicname}', rename);
        if (author != undefined && author != ""){
            if (duration != null && duration != -1){
                menu = menu.addButton(`§2${i}、 §r${content} §r§7[${StringSecend(parseDuration(duration)/1000)}] ${DataArry[musicName].hide ? "§3(隐藏)" : ""}\n§r§7§o${author}`);
            }else{
                menu = menu.addButton(`§2${i}、 §r${content} ${DataArry[musicName].hide ? "§3(隐藏)" : ""}\n§r§7§o${author}`);
            }
        }else{
            if (duration != null && duration != -1){
                 menu = menu.addButton(`§2${i}、 §r${content} §r§7[${StringSecend(parseDuration(duration)/1000)}] ${DataArry[musicName].hide ? "§3(隐藏)" : ""}`);
            }else{
                 menu = menu.addButton(`§2${i}、 §r${content} ${DataArry[musicName].hide ? "§3(隐藏)" : ""}`);
            }
           
        }
        
    }
    return menu;
}

// 播放音乐
function playMusic(pl, mode , musicName, R, musicMcName, volume, minimumVolume, xyz){
    // 停止播放
    mc.getOnlinePlayers().filter(player=>
        ((player.pos.x - pl.pos.x)**2 + 
        (player.pos.y - pl.pos.y)**2 + 
        (player.pos.z - pl.pos.z)**2) < R**2
    ).forEach(player=>{
        if (player.xuid != pl.xuid && player.xuid in PlayList){
            PlayList[player.xuid]["mode"] = undefined;
            PlayList[player.xuid]["endTime"] = undefined;
            PlayList[player.xuid]["xyz"] = undefined;
            PlayList[player.xuid]["R"] = undefined;
            PlayList[player.xuid]["volume"] = undefined;
            PlayList[player.xuid]["minimumVolume"] = undefined;
        }
        mc.runcmdEx(`execute as "${player.realName}" at @s positioned ~ ~ ~ run stopsound @s`);
        LRCremove(player, "right");
    });
    
    // 开始播放
    logger.debug(`========================`);
    logger.debug(`开始播放: ${mode} Name:${musicName}, R:${R}, McName:${musicMcName}, Vol:${volume}, miniVol:${minimumVolume}, Pos:`,xyz);
    if (mode == "record"){
        if (config.get("usrGUI")["lrc"] == true){
            LRCdisplay(pl, musicName, DataArry[musicName]['rename'], R, "musicbox");
        }
        mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run tellraw @a[r=${R}] {"rawtext":[{"text":"§a<${pl.realName}> §6播放音乐盒 - §r${DataArry[musicName]['rename']} §r| 范围:§b${R}"}]}`);
        if (xyz == undefined){
            mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run playsound ${musicMcName} @a[r=${R}] ~~~ ${volume} 1.0 ${minimumVolume}`);
        }else{
            mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run playsound ${musicMcName} @a[r=${R}] ${xyz.x} ${xyz.y} ${xyz.z} ${volume} 1.0 ${minimumVolume}`);
        }
    }

    if (mode == "bgm"){
        //显示歌词
        if (config.get("usrGUI")["lrc"] == true){
            LRCdisplay(pl, musicName, DataArry[musicName]['rename'], R, "BGM");
        }
        mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run tellraw @a[r=${R}] {"rawtext":[{"text":"§a<${pl.realName}> §6播放BGM - §r${DataArry[musicName]['rename']} §r| 范围:§b${R}"}]}`);
        mc.runcmdEx(`execute as "${pl.realName}" at @s positioned ~ ~ ~ run execute as @a[r=${R}] at @s run playsound ${musicMcName} @s ~~~  ${volume}`);                
    }
}

// 播放列表关键变量说明：
// endTime 为undefined 则歌曲暂停自动播放，或者没有歌曲时长不执行自动播放
// xyz 为判断音乐盒还是bgm的依据


// 当前播放列表检测（滤除已失效的音乐）
function CheckPlayList(xuid) {
    let pl = mc.getPlayer(xuid);
    if (!(xuid in PlayList)){
        return false;
    }
    let musicList = PlayList[xuid]["musicList"];
    let newMusicList = [];
    for(let i = 0; i< musicList.length; i++){
        if(DataArry[musicList[i]] != undefined){
            newMusicList.push(musicList[i]);
        }
    }
    if ((musicList.length - newMusicList.length) > 0){
        pl.sendText(`[LF_Music] §e播放列表中 ${musicList.length - newMusicList.length } 首音乐已失效`);
    }

    if (newMusicList.length == 0){
        delete PlayList[xuid];
        return false;
    }

    PlayList[xuid]["musicList"] = newMusicList;
    return true;
}

// 添加播放列表（不是立即播放）push
function addPlayList(pl, mode, musicName, R, musicMcName, volume, minimumVolume, xyz){
    // 歌曲时长是否能获取
    let endTime;
    if(DataArry[musicName]["duration"] == -1 || DataArry[musicName]["duration"] == null){
        endTime = undefined;
    }else{
        endTime = new Date().getTime() + parseDuration(DataArry[musicName]["duration"]);
    }

    // 播放列表初始化以及添加
    if (!(pl.xuid in PlayList)){
        PlayList[pl.xuid] = {
            playerName: pl.realName,
            musicList: [musicName],
            endTime: endTime, // 结束时间
            playOrder: "ListLoop",// 默认列表循环
            R:R,
            volume:volume,
            minimumVolume:minimumVolume,
            xyz:xyz  // 播放地点(音乐盒判断依据)
        };
    }else{
        if (PlayList[pl.xuid]["musicList"].indexOf(musicName) == -1){
            PlayList[pl.xuid]["musicList"].push(musicName);
            pl.sendText(`[LF_Music] §a添加到列表: §r${DataArry[musicName]["rename"]}`);
        }else{
            pl.sendText(`[LF_Music] §e歌曲已经在列表中了~`);
        }

    }
    debugPlaylist();
    
}

// 插入播放列表(立即播放 & 播放入口) unshift 
function insPlayList(pl, mode, musicName, R, musicMcName, volume, minimumVolume, xyz, isAutoPlay){
    // 歌曲时长是否能获取
    let endTime;
    if(DataArry[musicName]["duration"] == -1 || DataArry[musicName]["duration"] == null){
        endTime = undefined;
    }else{
        endTime = new Date().getTime() + parseDuration(DataArry[musicName]["duration"]);
    }

    // 播放列表初始化以及添加
    if (!(pl.xuid in PlayList)){
        PlayList[pl.xuid] = {
            playerName: pl.realName,
            mode:mode,
            musicList: [musicName],
            endTime: endTime, // 结束时间
            playOrder: "ListLoop",// 默认列表循环
            isAutoPlay: isAutoPlay,
            R:R,
            volume:volume,
            minimumVolume:minimumVolume,
            xyz:xyz  // 播放地点(音乐盒判断依据)
        };
        playMusic(pl, mode , musicName, R, musicMcName, volume, minimumVolume, xyz);
    }else{
    // 已有当前播放列表
        // 检查和滤除当前播放列表
        CheckPlayList(pl.xuid);

        // 更新列表：播放列表存在该歌曲——移除后重新置顶
        if (PlayList[pl.xuid]["musicList"].indexOf(musicName) != -1){
            PlayList[pl.xuid]["musicList"].splice(PlayList[pl.xuid]["musicList"].indexOf(musicName), 1);
        }
        PlayList[pl.xuid]["musicList"].unshift(musicName);

        // 重置所有播放参数
        PlayList[pl.xuid]["mode"] = mode;
        PlayList[pl.xuid]["R"] = R;
        PlayList[pl.xuid]["volume"] = volume;
        PlayList[pl.xuid]["minimumVolume"] = minimumVolume;
        PlayList[pl.xuid]["endTime"] = endTime;
        PlayList[pl.xuid]["isAutoPlay"] = isAutoPlay;
        if (mode == "record"){
            PlayList[pl.xuid]["xyz"] = xyz;
        }else{
            PlayList[pl.xuid]["xyz"] = undefined;
        }

        // 立即播放
        playMusic(pl, mode , musicName, R, musicMcName, volume, minimumVolume, xyz);
    }
    debugPlaylist();
}

// debug播放列表
function debugPlaylist(){
    for (let plXuid in PlayList){
        logger.debug(`========================`);
        logger.debug(`播放列表更新:`);
        if (DataArry[PlayList[plXuid]["musicList"][0]].duration != undefined){
            let duration = DataArry[PlayList[plXuid]["musicList"][0]].duration[0] * 60 + DataArry[PlayList[plXuid]["musicList"][0]].duration[1];
            logger.debug(`当前时间: ${(new Date().getTime()/1000).toFixed(0)}s 结束时间:${((PlayList[plXuid]["endTime"])/1000).toFixed(0)}s 音频时长: ${duration}s`);
        }else{
            logger.debug(`当前时间: ${(new Date().getTime()/1000).toFixed(0)}s 结束时间:${((PlayList[plXuid]["endTime"])/1000).toFixed(0)}s 音频时长: 未填写`);
        }
        
        if (PlayList[plXuid]["xyz"] != undefined){
            logger.debug(`播放坐标: ${PlayList[plXuid]["xyz"]["x"]}, ${PlayList[plXuid]["xyz"]["y"]}, ${PlayList[plXuid]["xyz"]["z"]}`);
        }
        
        logger.debug(`播放参数: Order:${PlayList[plXuid]["playOrder"]} R:${PlayList[plXuid]["R"]} Vol:${PlayList[plXuid]["volume"]} miniVol:${PlayList[plXuid]["minimumVolume"]}`);

        for (let i=0; i<PlayList[plXuid]["musicList"].length; i++){
            let musicName = PlayList[plXuid]["musicList"][i];
            logger.debug(`#${i+1}: ${musicName}`);
        }
    }
}

// 随机播放列表：数组洗牌
function shuffle(arr){
  for (let i = 0; i < arr.length; i++) {
    let randomIndex = Math.round(Math.random() * (arr.length - 1 - i)) + i;
    [arr[i], arr[randomIndex]] = [arr[randomIndex], arr[i]];
  }
  return arr;
}

// 解析音频时长 返回时长（单位毫秒）
function parseDuration(duration){
    if (duration == undefined){return undefined;}
    return duration[0]*60*1000 + duration[1]*1000;
}

//转换秒数为时间字符串 120-> 02:00
function StringSecend(secend){
    let min = ``;
    let sec = ``;
    if (Math.floor(secend/60) < 10){
        min = `0${Math.floor(secend/60)}`;
    }else{
        min = `${Math.floor(secend/60)}`;
    }
    if (secend%60 < 10){
        sec = `0${Math.floor(secend%60)}`;
    }else{
        sec = `${Math.floor(secend%60)}`;
    }
    return `${min}:${sec}`;
}

// FFmpeg 获取音频时长
function getMusicDuration(){
    let done = 0;
    var result = true;
    if (!File.exists(`${PATH.MAIN}/tools/ffmpeg.exe`)){
        logger.warn(`[ffmpeg] ffmpeg.exe未找到，你可以手动在data.json中填写歌曲时长: "duration":[分,秒]`);
        colorLog("yellow", `音乐更新完毕，请重启服务器`);
        return true;
    }
    var reg = /[\s\S]*Duration:\s*\d*:(\d*):(\d*).(\d*),[\s\S]*/;
    for (let musicName in DataArry){
        if (DataArry[musicName]["duration"] == -1 || DataArry[musicName]["duration"] == null){
            done ++;
            result = false;
            var ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -i "${PATH.MUSIC}/${musicName}.ogg" 2>&1 | findstr "Duration"`;
            system.newProcess(ffmpegcmd, (exitcode, output)=>{
                if (reg.test(output) == true){
                    let regResult = reg.exec(output);
                    //let duration = Number(regResult[1]) + Number(regResult[2])/100;
                    let duration = [Number(regResult[1]), Number(regResult[2])];

                    DataArry[musicName]["duration"] = duration;
                    DataCfg.set("music", DataArry);
                    log(`[ffmpeg] 获取音乐时长 ${musicName} ${duration}`);
                    done--;
                    if (done == 0){
                        colorLog("yellow", `[ffmpeg] 音乐时长更新完成`);
                        colorLog("yellow", `音乐更新完毕，请重启服务器`);
                        //refMusic(); //再次执行refmusic
                    }
                }
            });
        }
    }

    // if (result == true){
    //     logger.warn("请手动检查 data.json 中歌曲时长(duration)已填入，否则再次执行重载音乐指令");
    // }
    return result;
}

// FFmpeg 检测和转换音频格式
function checkAudioFormat(){
    var fl = File.getFilesList(PATH.MUSIC);
    var result = false; // 是否转换了音频
    done = 0;
    
    if (!File.exists(`${PATH.MAIN}/tools/ffmpeg.exe`)){
        logger.debug(`转换音频: 未找到 ${PATH.MAIN}/tools/ffmpeg.exe`);
        return;
    }
    
    if (!File.exists(`${PATH.MUSIC}/Backup`)){
        File.mkdir(`${PATH.MUSIC}/Backup/`);
    }

    for (let i = 0; i < fl.length; i++) {
        let reg = /^(.*)\.([A-Za-z0-9]+)$/;
        if (reg.test(fl[i]) == false){continue;}
        let fl_name = reg.exec(fl[i])[1]; // 文件名
        let fl_postfix = reg.exec(fl[i])[2].toLowerCase(); 

        if (["mp3","flac","m4a","wav","wma","mp2","midi","ra","ape"].indexOf(fl_postfix) != -1){
            // if (File.exists(`${PATH.MUSIC}/${fl_name}.ogg`)){
            //     log(`[ffmpeg] 跳过转换：${fl_name}.ogg 已存在`);
            //     if (!File.exists(`${PATH.MUSIC}/Backup/${fl[i]}`)){
            //         File.move(`${PATH.MUSIC}/${fl[i]}`, `${PATH.MUSIC}/Backup/`);     
            //     }else{
            //         File.delete(`${PATH.MUSIC}/${fl[i]}`);
            //     }
            //     continue;
            // }
            result = true;
            done ++;
            log("[ffmpeg] 正在转换音频格式.. "+fl[i]);
            //转换音频格式
            var ffmpegcmd;

            // 弹出窗口执行 ffmpeg.exe
            if (config.get("ffmpegExecuteMode") == "窗口"){
                switch(config.get("AudioConversionQuality")){
                    case "低质量":
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -fps_mode vfr -vn -ar 22050 -ab 32k -ac 2 -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;
                        break;
                    case "中质量":
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -fps_mode vfr -vn -ar 44100 -ab 128k -ac 2 -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;
                        break;
                    case "高质量":
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -vn -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;
                        break;
                    default: //默认低质量
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -fps_mode vfr -vn -ar 22050 -ab 32k -ac 2 -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;
                }
            }else if(config.get("ffmpegExecuteMode") == null){
                // 隐藏窗口执行 ffmpeg.exe
                switch(config.get("AudioConversionQuality")){
                    case "低质量":
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -fps_mode vfr -vn -ar 22050 -ab 32k -ac 2 -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;        
                        break;
                    case "中质量":
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -fps_mode vfr -vn -ar 44100 -ab 128k -ac 2 -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;
                        break;
                    case "高质量":
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -vn -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;
                        break;
                    default: //默认低质量
                        ffmpegcmd = `${PATH.MAIN}/tools/ffmpeg.exe -loglevel fatal -i "${PATH.MUSIC}/${fl[i]}" -acodec libvorbis -fps_mode vfr -vn -ar 22050 -ab 32k -ac 2 -nostdin -y ${PATH.MUSIC}/${fl_name}.ogg`;
                }
            }
            system.newProcess(ffmpegcmd, (exitcode, output)=>{
                if(exitcode == 0){
                    //备份原始音频文件
                    if (!File.exists(`${PATH.MUSIC}/Backup/${fl[i]}`)){
                        File.move(`${PATH.MUSIC}/${fl[i]}`, `${PATH.MUSIC}/Backup/`);     
                    }else{
                        File.delete(`${PATH.MUSIC}/${fl[i]}`);
                    }
                    log(`[ffmpeg] ${fl_name}.ogg | 转换完成: ${(File.getFileSize(`${PATH.MUSIC}/${fl_name}.ogg`)/1024/1024).toFixed(2)}MB`);

                    done--;
                    if (done <= 0 ){
                        colorLog("yellow", `[ffmpeg] 音频转换完成 (模式: ${config.get("AudioConversionQuality")})`);
                        refMusic();
                    }
                }else{
                    logger.error(`${fl[i]} 转换失败`);
                    logger.error(`${output}`);
                }
            },25000);
        }
    }
    return result;
}


// 歌曲重命名格式化
function format(str, obj) {
    //str 为字符串 obj 为替代对象 例如 {name:"me"} str 替代表达式{name}
    if (typeof (str) == "string" && typeof (obj) == "object") {
        for (let key in obj) {
            let reg = new RegExp("({" + key + "})", "g");
            str = str.replace(reg, obj[key]);
        }
        return str;
    } else {
        logger.error("格式化字符串出错");
        return "error";
    }
}

// 随机整数
function getRandomIntInclusive(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min; //含最大值，含最小值
}

// 反馈结束菜单
function menu_end(pl,title,endmsg,lastForm,lastForm_run){
    var menu_end = mc.newSimpleForm();
    menu_end.setTitle(title);
    menu_end.setContent('\n\n'+endmsg+'\n\n\n\n');
    menu_end.addButton('§6§l退出菜单');
    if (lastForm != undefined){
        menu_end.addButton('§l返回上一页');
    }
    
    pl.sendForm(menu_end,function(pl,id){
        if (id == null){return '菜单已放弃';}
        if (id == 1){
            pl.sendForm(lastForm,lastForm_run);
            return '返回上一页';
        }
    });
}
// 歌词顶部字幕
// var RUNTIME = 0; //显示歌词的绝对时间（毫秒）
// var bias = -50; // 所有歌曲歌词时间偏移
// var LRCdata = {}; //读取歌词长期存在内存中


// var CurrentMusic = {}; //正在播放的音乐 当前显示歌词的信息，控制什么时候显示歌词
//{pl.realName: {nextTime, musicName, lrcIndex, lrcSwitch, startTime, totalTime, boxPos}}
//{下次播放的时间戳，歌曲文件名，下次显示的歌词数组索引，显示歌词开关，开始播放的时间戳，歌词总时长, 音乐盒播放地点}


//时间循环100ms 播放列表自动播放 歌词实时更新

setInterval(function(){
    //当前时间;
    RUNTIME = new Date().getTime();

    //音乐到点播放
    if (PlayList.length != 0){
        LoopPlay(RUNTIME);
    }

    // 全服BGM
    if (BGM_enabled){BGM();}
    function BGM(){
        if (CurrentBGM.endTime != 0 && RUNTIME < CurrentBGM.endTime){return;} // 当前音乐未结束

        // 歌曲结束随机一个音乐
        if (cache_BGMlist.length == 0){
            cache_BGMlist = bgm_cfg.get("playList");
            if (cache_BGMlist == null || cache_BGMlist.length == 0){
                return;
            }
        }
        
        let rollIndex = Math.round(Math.random()*(cache_BGMlist.length-1));
        let musicName = cache_BGMlist[rollIndex];
        cache_BGMlist.splice(rollIndex, 1);

        // log(cache_BGMlist)
        // log(`当前全服BGM: ${musicName} now:${RUNTIME} end:${CurrentBGM.endTime} ${rollIndex}`)
        
       // 是否能播放
        if (DataArry[musicName] == null || DataArry[musicName]["duration"] == -1 || DataArry[musicName]["duration"] == null){
            let playList = bgm_cfg.get("playList");
            playList.splice(playList.indexOf(musicName), 1); // 去除无时长音乐
            bgm_cfg.set("playList", playList);
            mc.broadcast(`§7一首音乐无法作为BGM`);
            logger.warn(`${musicName} 无法作为BGM, 因为其被移除或没有获取到音乐时长`);
            return;
        }

        // 播放
        CurrentBGM.musicName = musicName;
        CurrentBGM.endTime = RUNTIME + parseDuration(DataArry[CurrentBGM.musicName]["duration"]) + 1000 * getRandomIntInclusive(bgm_cfg.get("minRandomInterval"), bgm_cfg.get("maxRandomInterval"));
        mc.runcmdEx(`music play music.game.${CurrentBGM.musicName} ${bgm_cfg.get("volume")} 2 play_once`);
    }

    // 播放列表自动播放
    function LoopPlay(){
        RUNTIME = new Date().getTime();
        for (let plXuid in PlayList){
            var pl = mc.getPlayer(plXuid);

            // 玩家下线
            if (pl == null){continue;} 

            // 不执行播放列表自动播放
            if (PlayList[plXuid]["endTime"] == undefined){continue;} 

            // 当前歌曲结束时间未到
            if (RUNTIME < PlayList[plXuid]["endTime"]){continue;}

            // 按播放顺序更新播放列表
            switch(PlayList[plXuid]["playOrder"]){
                case "Loop":
                    break;
                case "ListLoop":
                    PlayList[plXuid]["musicList"].push(PlayList[plXuid]["musicList"].shift());
                    break;
                case "Random": //这是骗人的，随机逻辑在表单那里(打乱数组)。
                    PlayList[plXuid]["musicList"].push(PlayList[plXuid]["musicList"].shift());
                    break;
                default:
                    logger.error("播放顺序字符串错误");
            }
            
            // 获取下首歌曲文件名（无后缀）
            let allowPlay = 0;
            let musicName = PlayList[plXuid]["musicList"][0];

            // 过滤无音乐时长的音乐
            while(allowPlay == 0){
                musicName = PlayList[plXuid]["musicList"][0];
                // 没有歌曲时长信息
                if (DataArry[musicName]["duration"] == -1 || DataArry[musicName]["duration"] == null){
                    pl.sendText(`[LF_Music] §e跳过 §r${DataArry[musicName]["rename"]}§r§e, 未能获取音乐时长`); 
                    PlayList[plXuid]["musicList"].shift(); //删除没有时长的歌曲
                    continue;
                }

                // 去除歌曲后没有歌曲
                if (PlayList[plXuid]["musicList"].length == 0){
                    pl.sendText(`[LF_Music] §e播放列表里没有音乐了`); 
                    delete PlayList[plXuid]; // 清空播放列表
                    allowPlay = -1;
                    break;
                }
                allowPlay = 1;
            }

            // 滤除后播放列表已没有音乐
            if (allowPlay == -1){
                continue;
            }
            // allowPlay = 1
            // 是否自动播放下一首(停止播放)
            if (PlayList[plXuid]["isAutoPlay"]  == false){
                PlayList[pl.xuid]["mode"] = undefined;
                PlayList[pl.xuid]["endTime"] = undefined;
                PlayList[pl.xuid]["xyz"] = undefined;
                PlayList[pl.xuid]["R"] = undefined;
                PlayList[pl.xuid]["volume"] = undefined;
                PlayList[pl.xuid]["minimumVolume"] = undefined;
                LRCremove(pl, "right");
                continue;
            }

            //播放下一首音乐
            PlayList[plXuid]["endTime"] = RUNTIME + parseDuration(DataArry[musicName]["duration"]); //更新歌曲结束时间 —— 下首歌曲开始时间
            if (PlayList[plXuid]["xyz"] == undefined){
                playMusic(pl, "bgm", musicName, PlayList[plXuid].R, `music.game.${musicName}`, PlayList[plXuid].volume, PlayList[plXuid].minimumVolume);
            }else{
                playMusic(pl, "record", musicName, PlayList[plXuid].R, `record.${musicName}`, PlayList[plXuid].volume, PlayList[plXuid].minimumVolume, PlayList[plXuid]["xyz"]);
            }
            logger.debug(`【自动播放】 自动播放下一首，时长: ${parseDuration(DataArry[musicName]["duration"])}`);
            debugPlaylist();  // debug
        }
    }
    
    //没有玩家播放带歌词的音乐则不执行歌词显示
    if (CurrentMusic == {}){return;}

    // 歌词到点显示
    for (let key in CurrentMusic){
        var pl = mc.getPlayer(key);
        if (pl == null){
            delete CurrentMusic[key];
            continue;
        } //找不到人则跳过该玩家的显示
        let Musicing = CurrentMusic[key];
        //if (Musicing.nextLrcTime == undefined){continue;} //没有歌词则跳过该玩家的显示

        //到点更新歌词
        if (Musicing.havelrc && RUNTIME >= Musicing.nextLrcTime){
            //后面还有歌词
            if (LRCdata[Musicing.musicName][0][Musicing.nextLrcIndex + 1] != undefined){
                //本次歌词显示总时间(下次出现时间 - 本次出现时间)
                var nextInterval = LRCdata[Musicing.musicName][0][Musicing.nextLrcIndex + 1] - LRCdata[Musicing.musicName][0][Musicing.nextLrcIndex];
                
                // 更新顶部歌词显示（歌曲无时长信息，则按歌词时长显示进度）
                if (Musicing.lrcSwitch){
                    if (Musicing.totalTime == undefined){ //无时长信息，按歌词时长
                        let progress = Math.floor((RUNTIME - Musicing.startTime) / Musicing.totalLrcTime * 100);
                        if (config.get('usrGUI').lrcDisplay == "Popup"){
                            pl.tell(LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], 4);
                        }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                            pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], progress, 0);
                        }
                    }else{ //有时长信息
                        let progress = Math.floor((RUNTIME-Musicing.startTime)/Musicing.totalTime * 100);
                        if (config.get('usrGUI').lrcDisplay == "Popup"){
                            pl.tell(LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], 4);
                        }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                            pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], progress, 0);
                        }
                    } 
                }
                  
                
                // lrc文件内自定义歌词偏移
                var customBias = LRCdata[Musicing.musicName][2];
                Musicing.nextLrcTime = (Musicing.nextLrcTime_std + bias + customBias) + nextInterval ; // 下下次歌词显示的绝对时间戳 对绝对时间进行偏移
                Musicing.nextLrcTime_std = Musicing.nextLrcTime_std + nextInterval;
                //log(`std: ${Musicing.nextLrcTime_std} real: ${Musicing.nextLrcTime}`)
                Musicing.nextLrcIndex ++;

            }else{ //后面没有歌词

                // 显示最后一行歌词
                if (Musicing.lrcSwitch){ // 该玩家打开了歌词开关（默认为开）
                    if (Musicing.totalTime == undefined){ 
                        if (config.get('usrGUI').lrcDisplay == "Popup"){
                            pl.tell(LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], 4);
                        }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                            pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], 100, 0);
                        }
                    }else{
                        let progress = Math.floor((RUNTIME-Musicing.startTime)/Musicing.totalTime * 100);
                        if (config.get('usrGUI').lrcDisplay == "Popup"){
                            pl.tell(LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], 4);
                        }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                            pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], progress, 0);
                        }
                    }
                }
                
                //无时长信息, 歌词结束后延迟10秒关闭歌词
                if (Musicing.totalTime == undefined){ 
                    LRCremove(pl, "delay");
                }
                // 歌曲暂停自动播放， 则10秒后自动关闭歌词
                // if (pl.xuid in PlayList){
                //     if (PlayList[pl.xuid].endTime == undefined){
                //         LRCremove(pl, "delay");
                //     }
                // }
            }
        }
            
        //保持显示
        if (Musicing.lrcSwitch){
            if (Musicing.totalTime != undefined){ // 填写了歌词时长
                let secend = Math.floor((RUNTIME-Musicing.startTime)/1000);
                let progress = Math.floor((RUNTIME-Musicing.startTime)/Musicing.totalTime * 100);
                if (secend != Musicing.secend){
                    if (secend > (Musicing.totalTime/1000)){ // 歌词结束
                        LRCremove(pl, "right");
                        continue;
                    }
                    if (Musicing.havelrc){
                        if (Musicing.nextLrcIndex > 0){
                            if (Musicing.nextLrcIndex < LRCdata[Musicing.musicName][1].length - 1){
                                // 除第一句和最后一句
                                if (config.get('usrGUI').lrcDisplay == "Popup"){
                                    pl.tell(LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex-1], 4);
                                }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                                    pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex-1], progress, 0);
                                }
                            }else{
                                // 最后一句歌词
                                if (config.get('usrGUI').lrcDisplay == "Popup"){
                                    pl.tell(LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], 4);
                                }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                                    pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), LRCdata[Musicing.musicName][1][Musicing.nextLrcIndex], progress, 0);
                                }
                            }
                        }else{
                            if (config.get('usrGUI').lrcDisplay == "Popup"){
                                pl.tell(`§a请欣赏: §d${Musicing.musicRename}   §r§7${StringSecend(secend)} | ${StringSecend(Musicing.totalTime/1000)}`, 4);
                            }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                                pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), `§a请欣赏: §d${Musicing.musicRename}   §r§7${StringSecend(secend)} | ${StringSecend(Musicing.totalTime/1000)}`, progress, 0);
                            }
                        }
                    }else{
                        if (config.get('usrGUI').lrcDisplay == "Popup"){
                            pl.tell(`§a请欣赏: §d${Musicing.musicRename}   §r§7${StringSecend(secend)} | ${StringSecend(Musicing.totalTime/1000)}`,4);
                        }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                            pl.setBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)), `§a请欣赏: §d${Musicing.musicRename}   §r§7${StringSecend(secend)} | ${StringSecend(Musicing.totalTime/1000)}`, progress, 0);
                        }
                    }
                    Musicing.secend = secend;
                }
            }
        }
    }
},200);

// 给一个玩家显示对应歌曲的歌词
function LRCdisplay(pl, musicName, musicRename, R, mode){
    //发出播放指令的玩家，歌曲文件名，歌曲重命名，播放半径

    var now = new Date();
    var havelrc = false;

    //读入歌曲对应歌词
    if (File.exists(`${PATH.MUSIC}/${musicName}.lrc`)){
        if (LRCdata[musicName] == undefined){
            LRCdata[musicName] = LRCparse(musicName);
        }
        havelrc = true;
        //debug
        //log(`读入歌词: ${PATH.MUSIC}/${musicName}.lrc`)
    }
 

    // 播放半径内的玩家歌词显示
    // 有歌词和没歌词都要注册进歌词循环中

    mc.getOnlinePlayers().filter(player=>
        ((player.pos.x - pl.pos.x)**2 + 
        (player.pos.y - pl.pos.y)**2 + 
        (player.pos.z - pl.pos.z)**2) < R**2
    ).forEach(pl_1=>{
        if (havelrc){
            if (config.get('usrGUI').lrcDisplay == "Popup"){
                pl.tell(`§a请欣赏: §d${musicRename}`,4);
            }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                pl_1.setBossBar(Math.floor((Number(pl_1.xuid) / 2 + 1027)), `§a请欣赏: §d${musicRename}`, 100, 0);
            }
            // 给该玩家初始化当前显示歌词的信息
            //{nextTime, musicName, lrcIndex, lrcSwitch, startTime, totalTime}}
            
            var customBias = LRCdata[musicName][2];
            CurrentMusic[pl_1.xuid] = {
                musicName: musicName,
                musicRename: musicRename,
                totalTime: parseDuration(DataArry[musicName].duration), //歌曲时长
                secend: 0, //当前秒数
                startTime: now.getTime(),

                havelrc: havelrc,
                totalLrcTime: LRCdata[musicName][0][LRCdata[musicName][0].length - 1], //歌词时长
                nextLrcTime: now.getTime() + LRCdata[musicName][0][0] + bias + customBias, 
                nextLrcTime_std: now.getTime() + LRCdata[musicName][0][0],
                nextLrcIndex: 0, 
                lrcSwitch: true, // 歌词显示开
            };
            // if (mode == "musicBox"){
            //     CurrentMusic[pl_1.realName]["boxPos"] = [pl.blockPos.x, pl.blockPos.y, pl.blockPos.z, pl.blockPos.dimid];
            // }

        }else{
            if (config.get('usrGUI').lrcDisplay == "Popup"){
                pl.tell(`§a请欣赏: §d${musicRename}`,4);
            }else if (config.get('usrGUI').lrcDisplay == "Bossbar"){
                pl_1.setBossBar(Math.floor((Number(pl_1.xuid) / 2 + 1027)), `§a请欣赏: §d${musicRename}`, 100, 0);
            }
            let totalTime = parseDuration(DataArry[musicName].duration);
            if (totalTime  != undefined){
                CurrentMusic[pl_1.xuid] = {
                    musicName: musicName,
                    musicRename: musicRename,
                    totalTime: totalTime, //歌曲时长
                    secend: 0, //当前秒数
                    startTime: now.getTime(),
    
                    havelrc: havelrc,
                    lrcSwitch: true  // 歌词显示开
                };
            }
        }
    }); 
    
}

// 歌词lrc文件读取与解析
function LRCparse(musicName){
    let LrcParseList = [[],[],0];
    //[歌词显示时间, 歌词文本, 歌词偏移]
    //let lrcreg = /^\w+\.lrc$/; //lrc正则
    let lrc = File.readFrom(`${PATH.MUSIC}/${musicName}.lrc`);
    let lrcList1 = lrc.split("\n");
    let reg = /\[(\d*):(.*?)\](.*)/;
    let biasReg = /歌词偏移\s*=\s*((\-|\+)?\d+)/;
    for (let i = 0; i<lrcList1.length; i++){

        // 读取歌词偏移
        if (biasReg.test(lrcList1[i]) == true){
            LrcParseList[2] = Number(biasReg.exec(lrcList1[i])[1]);
        }

        // 跳过非歌词行
        if (reg.test(lrcList1[i]) == false){continue;}
        
        let time = Number(reg.exec(lrcList1[i])[1]) * 60 * 1000 + Number(reg.exec(lrcList1[i])[2]) * 1000; // 单位是毫秒
        let text = reg.exec(lrcList1[i])[3];

        //debug 歌词解析结果
        //log("读取歌词: "+ time+" > "+text);

        // 读取歌词及翻译
        let timeIdex = LrcParseList[0].indexOf(time);
        if (timeIdex == -1){
            LrcParseList[0].push(time);
            LrcParseList[1].push("§b"+text);
        }else{
            //LrcParseList[1][timeIdex] = LrcParseList[1][timeIdex].replace(/b/, 'f') + " / §b" + text;
            LrcParseList[1][timeIdex] = LrcParseList[1][timeIdex].replace(/b/, 'f') + "\n§b" + text;
        }
        
    }
    return LrcParseList;
    //[[time(ms),time,],[lrc, lrc, lrc,]]
}

// 延迟去掉顶部歌词
function LRCremove(pl, mode){
    if (CurrentMusic[String(pl.xuid)] != undefined){
        delete CurrentMusic[pl.xuid];
    }

    if (mode == "delay"){
        setTimeout(function(){
            // 十秒后去掉顶部歌词
            if (pl.xuid in PlayList){
                if (PlayList[pl.xuid].endTime == undefined){
                    pl.removeBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)));
                }
            }
            
        },10000);
    }else{
        pl.removeBossBar(Math.floor((Number(pl.xuid) / 2 + 1027)));
    }
}




// LLSE_Player.prototype.stopSound = 
// /** 
//  * 发送停止播放音效数据包
//  * @param {String?} sound 音效ID
// */
// function (sound = null) {
//     const stopSoundPacket = new Binarystream();
//     stopSoundPacket.writeString(sound ?? '');
//     stopSoundPacket.writeBool(sound == nul1);
//     this.sendPacket(stopSoundPacket.createPacket(0x58));
// };

// LLSE_Player.prototype.playSound =
// /**
//  * 发送播放音频数据包
//  * @param {String} sound 音效ID
//  * @param {Number} volume 音量
//  * @param {Number} tones 音调
//  * @returns
// */
// function (sound, volume = 1, tones = 1) {
//     const bs = new Binarystream();
//     bs.writeString(sound);
//     bs.writeVarInt(Math.round(Player.pos.x * 8));
//     bs.writeUnsignedVarInt(Math.round((Player.pos.y + 0.37) * 8));
//     bs.writeVarInt(Math.round(Player.pos.z * 8));
//     bs.writeFloat(volume);
//     bs.writeFloat(tones);
//     return this.sendPacket(bs.createPacket(0x56));
// };



// if (ll.hasExported('ILAPI_GetPlayerLands')) {
//     ILAND = {
//         Listen: ll.import('ILAPI_AddBeforeEventListener'),
//         AfterListen: ll.import('ILAPI_AddAfterEventListener'),
//         PosGetLand: ll.import('ILAPI_PosGetLand'), //根据坐标查询领地 pos -> landid
//         GetOwner: ll.import('ILAPI_GetOwner'), // 查询领地主人 landid -> xuid
//         IsLandOwner: ll.import('ILAPI_IsLandOwner'), // 查询是否为领地主人 landid xuid -> bool
//         GetPlayerLands: ll.import('ILAPI_GetPlayerLands'), // 查询玩家所有领地 xuid -> [landid, ]
//         GetName: ll.import('ILAPI_GetName'), // 获取领地名称 landid -> name
//     };
//     ILAND.AfterListen('onEnter', 'onEnter');
//     ILAND.AfterListen('onLeave', 'onLeave');
// }else{
//     //logger.error(`iland API 未导入, 本插件会运行错误, 请检查是否安装iland`);
// }

// let iland_cfg = new JsonConfigFile(`${PATH.MAIN}/iland.json"`); //配置文件
// function onEnter(landid, xuid){
//     let landMusicInfo =  iland_cfg.get(landid);
//     if (landMusicInfo?.music == null){return;}
//     let pl = mc.getPlayer(xuid);
//     if (pl == null){return;}
//     pl.runcmd(`playsound music.game.${landMusicInfo.musicName} @s`);
// }
// function onLeave(landid, xuid){
//     let pl = mc.getPlayer(xuid);
//     if (pl == null){return;}
//     pl.runcmd(`playsound music.game.${landMusicInfo.musicName} @s`);
// }